package com.group.controller;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.base.view.ListResult;
import com.group.dao.InviteRebateDao;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Controller;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.view.RedirectView;

import com.base.view.BaseResult;
import com.base.view.GeneralResult;
import com.group.model.*;
import com.group.util.NoteException;
import com.group.util.WeiXinConf;
import com.group.util.WeiXinUtils;

/**
 * wecc 等不走币行的提现
 * 
 * @author zhaolei
 *
 */
@Controller
public class WeccPaymentController extends BaseController {
	private static final Logger logger = LoggerFactory.getLogger(WeccPaymentController.class);

	@Autowired
	InviteRebateDao inviteRebateDao;

	/**
	 * url跳转,去wecc微信取openid
	 * 
	 * @param id
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	@RequestMapping("/wecc/auth/openid")
	public RedirectView urlRedirect(Long id, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
		if (id == null) {
			throw new NoteException("id 不能为空");
		}

		String agent = request.getHeader("user-agent");
		// logger.info("urlRedirect agent : " + agent);

		try {
			User user = getUser(request);
			if (StringUtils.isNotEmpty(user.getWeccOpenid())) {
				String url = beanDao.quickQueryOne(UrlMapping.class, "id", id).getUrl();

				logger.info("用户user id = " + user.getId() + "wecc openId已经缓存，直接跳转 : " + url);
				return new RedirectView(url);
			}

		} catch (Exception e) {

		}

		// 微信授权
		String wxurl = WeiXinUtils.createWeccBaseUrl(id + "", getSystemParaValue("baseUrl") + "/v1/wecc/auth/redirect");
		logger.info(" 微信授权openid跳转到 url = " + wxurl);

		return new RedirectView(wxurl);
	}

	/**
	 * 获取openid
	 * 
	 * @param request
	 * @param state
	 * @param code
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/wecc/auth/redirect", method = RequestMethod.GET)
	@ResponseBody
	public RedirectView redirect(HttpServletRequest request, String state, String code, HttpServletResponse response) throws Exception {
		// 获取openid
		logger.info("微信接口回调 : code = " + code + " , state = " + state);
		WeccWeiXinToken token = new WeccWeiXinToken(code);
		String openid = token.getOpenid();

		// 补充user上的weccopenid
		User user = getUser(request);
		user.setWeccOpenid(openid);
		beanDao.save(user);

		Long umId = Long.parseLong(state);

		UrlMapping um = beanDao.quickQueryOne(UrlMapping.class, "id", umId);
		if (um == null) {
			throw new NoteException("error");
		}

		return new RedirectView(um.getUrl());
	}

	//

	/**
	 * 自己平台币的提现, 如:wecc
	 * 
	 * @param amount
	 *            数量
	 * @param cid
	 * @param reason
	 *            提现到现金,提现到钱包
	 * 
	 * @param address
	 *            钱包地址
	 * @param request
	 * @return
	 * @throws Exception
	 */
	@GetMapping("/wecc/payment/cash")
	@ResponseBody
	public synchronized BaseResult cash(Double amount, String cid, String reason, String address, HttpServletRequest request) throws Exception {
		if (reason == null)
			reason = "提现到现金";

		if (!"提现到钱包".equals(reason) && !"提现到现金".equals(reason) && !"提现到交易所".equals(reason))
			throw new NoteException("reason 错误");

		int limit = getSystemParaValueInt("wecclimit");
		double fee = 0d;

		if (!"提现到现金".equals(reason)) {
			fee = 300d;
			if (amount < 1500)
				throw new NoteException("提现不能少于1500");
		}

		if (amount < limit)
			throw new NoteException("提现数额必须大于" + limit);

		if (StringUtils.isEmpty(cid))
			throw new NoteException("cid 不能为空");

		double weccCash = getSystemParaValueDouble("weccCash");
		if ("提现到现金".equals(reason))
			if ((amount - fee) * weccCash > 19900)
				throw new NoteException("提现金额不能大于200元");

		User user = getUser(request);

		UserTicker ut = tickerService.getUserTicker(user.getId(), cid);

		if (ut == null)
			throw new NoteException("用户钱包不存在");

		if (ut.getNum().doubleValue() < amount)
			throw new NoteException("余额不足");

		tickerService.addTicker(user.getId(), cid, -amount, reason, null, "进行中", getBillNum(), fee, address);

		return new BaseResult();
	}

	/**
	 * 获取wecctoken
	 * 
	 * @return
	 */
	@GetMapping("/wecc/payment/token")
	@ResponseBody
	public BaseResult getToken() {

		return new BaseResult().setMessage(weiXinUtils.getToken() + "---" + weiXinUtils.getJsToken());
	}

	/**
	 * 前台获取jstoken
	 * 
	 * @param url
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/wecc/wxconfig", method = RequestMethod.GET)
	@ResponseBody
	public GeneralResult<JsTicket> getWxconfig(String url) throws Exception {
		JsTicket jt = weiXinUtils.getWeccJsTicket(url);

		return new GeneralResult<JsTicket>().setValue(jt);
	}

	// ------------------------------------------------------------支付接口
	// -----------------------------------------------------------------
	/**
	 * 预支付接口
	 * 
	 * @param openid
	 *            wecc的openid
	 * @param userId
	 * @param amount
	 *            购买币的数量
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/wecc/pay/prepay", method = RequestMethod.GET)
	@ResponseBody
	public GeneralResult<JSAPI> prepay(String openid, Long userId, Integer amount) throws Exception {
		if (StringUtils.isEmpty(openid) || userId == null || amount == null) {
			throw new NoteException("openid ,userId , amount 不能为空");
		}

		// fee = "0.01";

		File file = new ClassPathResource("/prepay.txt").getFile();

		String xml = FileUtils.readFileToString(file);

		String body = getSystemParaValue("wxpayMsg");
		String noncestr = "feifan250";
		String notifyUrl = getSystemParaValue("baseUrl") + "/v1/wecc/pay/notify";
		// String openid = "ofLmEwbf21cDMNSxWThSrc-VpVyg";
		String outTradeNo = getBillNum();

		int fee = (int) (getSystemParaValueDouble("weccBuy") * amount);
		OutTradeNoLog log = new OutTradeNoLog();
		log.setState(0);
		log.setOutTradeNo(outTradeNo);
		log.setUserId(userId);
		log.setFee(fee);
		log.setAmount(amount);
		beanDao.save(log);

		// 额外信息
		String attach = userId.toString() + "-" + outTradeNo + "-" + fee;
		String ip = "127.0.0.1";

		// String fee = getSystemParaValue("registFee");
		String totalFee = fee + "";

		xml = xml.replace("$appid", WeiXinConf.WECCAPPID);
		xml = xml.replace("$attach", attach);
		xml = xml.replace("$body", body);
		xml = xml.replace("$mchid", WeiXinConf.WECC_SHOP_ID);
		xml = xml.replace("$noncestr", noncestr);
		xml = xml.replace("$notifyUrl", notifyUrl);
		xml = xml.replace("$openid", openid);
		xml = xml.replace("$outTradeNo", outTradeNo);
		xml = xml.replace("$ip", ip);
		xml = xml.replace("$totalFee", totalFee);

		String signStr = "appid=" + WeiXinConf.WECCAPPID + "&attach=" + attach + "&body=" + body + "&mch_id=" + WeiXinConf.WECC_SHOP_ID + "&nonce_str=" + noncestr + "&notify_url=" + notifyUrl + "&openid="
				+ openid + "&out_trade_no=" + outTradeNo + "&spbill_create_ip=" + ip + "&total_fee=" + totalFee + "&trade_type=JSAPI&key=" + WeiXinConf.WECC_SHOP_SECRET;

		String sign = WeiXinUtils.getMD5Code(signStr).toUpperCase();
		xml = xml.replace("$sign", sign);

		String result = weiXinUtils.postNow(xml, "https://api.mch.weixin.qq.com/pay/unifiedorder");

		// 封装jsapi
		JSAPI api = new JSAPI();
		String appId = WeiXinConf.WECCAPPID;
		String signType = "MD5";
		String timeStamp = System.currentTimeMillis() / 1000 + "";
		Document doc = DocumentHelper.parseText(result);
		Element root = doc.getRootElement();
		String prepayId = root.element("prepay_id").getText();

		String signstr1 = "appId=" + appId + "&nonceStr=" + noncestr + "&package=prepay_id=" + prepayId + "&signType=MD5&timeStamp=" + timeStamp + "&key=" + WeiXinConf.WECC_SHOP_SECRET;
		logger.info("jsapi sign = " + signstr1);
		api.setAppId(appId);
		api.setNonceStr(noncestr);
		api.setPackage1("prepay_id=" + prepayId);
		api.setSignType(signType);
		api.setTimeStamp(timeStamp);
		api.setPaySign(DigestUtils.md5Hex(signstr1).toUpperCase());
		logger.info(api.getPaySign() + " --- " + WeiXinUtils.getMD5Code(signstr1).toUpperCase());

		return new GeneralResult<JSAPI>().setValue(api);
	}

	/**
	 * 支付成功后通知接口
	 * 
	 * @throws IOException
	 */
	@RequestMapping(value = "/wecc/pay/notify")
	public void payNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {

		String callback = StreamUtils.copyToString(request.getInputStream(), Charset.forName("utf8"));
		logger.info("支付成功回调 callback xml = " + callback);

		// 校验签名
		Document doc = DocumentHelper.parseText(callback);
		Element root = doc.getRootElement();
		String appid = root.element("appid").getText();
		String attach = root.element("attach").getText();
		String bank_type = root.element("bank_type").getText();
		String cash_fee = root.element("cash_fee").getText();
		String fee_type = root.element("fee_type").getText();
		String is_subscribe = root.element("is_subscribe").getText();
		String mch_id = root.element("mch_id").getText();
		String nonce_str = root.element("nonce_str").getText();
		String openid = root.element("openid").getText();
		String out_trade_no = root.element("out_trade_no").getText();
		String result_code = root.element("result_code").getText();
		String return_code = root.element("return_code").getText();
		String time_end = root.element("time_end").getText();
		String total_fee = root.element("total_fee").getText();
		String trade_type = root.element("trade_type").getText();
		String transaction_id = root.element("transaction_id").getText();
		String sign = root.element("sign").getText();
		String coupon_count = root.elementText("coupon_count");
		String coupon_fee = root.elementText("coupon_fee");
		String coupon_fee_0 = root.elementText("coupon_fee_0");
		String coupon_id_0 = root.elementText("coupon_id_0");

		// 支付失败
		if (!"success".equalsIgnoreCase(result_code)) {
			StreamUtils.copy("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>", Charset.forName("utf8"), response.getOutputStream());
			return;
		}
		String str = "";

		if (StringUtils.isEmpty(coupon_count))
			str = "appid=" + appid + "&attach=" + attach + "&bank_type=" + bank_type + "&cash_fee=" + cash_fee + "&fee_type=" + fee_type + "&is_subscribe=" + is_subscribe + "&mch_id=" + mch_id + "&nonce_str="
					+ nonce_str + "&openid=" + openid + "&out_trade_no=" + out_trade_no + "&result_code=" + result_code + "&return_code=" + return_code + "&time_end=" + time_end + "&total_fee=" + total_fee
					+ "&trade_type=" + trade_type + "&transaction_id=" + transaction_id + "&key=" + WeiXinConf.WECC_SHOP_SECRET;
		else {
			str = "appid=" + appid + "&attach=" + attach + "&bank_type=" + bank_type + "&cash_fee=" + cash_fee + "&coupon_count=" + coupon_count + "&coupon_fee=" + coupon_fee + "&coupon_fee_0=" + coupon_fee_0
					+ "&coupon_id_0=" + coupon_id_0 + "&fee_type=" + fee_type + "&is_subscribe=" + is_subscribe + "&mch_id=" + mch_id + "&nonce_str=" + nonce_str + "&openid=" + openid + "&out_trade_no="
					+ out_trade_no + "&result_code=" + result_code + "&return_code=" + return_code + "&time_end=" + time_end + "&total_fee=" + total_fee + "&trade_type=" + trade_type + "&transaction_id="
					+ transaction_id + "&key=" + WeiXinConf.WECC_SHOP_SECRET;
		}

		if (!sign.equals(WeiXinUtils.getMD5Code(str).toUpperCase()))
			throw new NoteException("签名校验失败");

		// 处理支付成功后事件
		String userIdStr = attach.split("-")[0];
		String outTradeNo = attach.split("-")[1];
		String fee = attach.split("-")[2];

		OutTradeNoLog log = beanDao.quickQueryOne(OutTradeNoLog.class, "outTradeNo", outTradeNo);
		if (log != null && log.getState() == 0) {
			Long userId = Long.parseLong(userIdStr);

			log.setOutTradeNo(outTradeNo);
			log.setState(1);
			beanDao.save(log);

			// 充值余额
			tickerService.addTicker(userId, "wecc", log.getAmount().doubleValue(), "充值");

			//返佣
			//rw:邀请我的人的钱包
			ReferenceWallet rw = inviteRebateDao.selectRefUserId(userId);
			if(rw != null){
				double rate = Double.parseDouble(beanDao.quickQueryOne(SystemPara.class, "name", "inviteRebatePercentage").getValue());
				inviteRebateDao.updateByVersion(rw.getWallet()+log.getAmount().doubleValue()*rate, rw.getUserId(), rw.getVersion());
				ReferenceDetail rd = new ReferenceDetail();
				rd.setUserId(rw.getUserId());
				rd.setRefUserId(userId);
				rd.setCreateDate(System.currentTimeMillis());
				rd.setChange(rw.getWallet() + log.getAmount().doubleValue()*rate);
				rd.setVersion(rw.getVersion());
				rd.setInvestment(log.getAmount().doubleValue());
				rd.setRebate(log.getAmount().doubleValue()*rate);
				rd.setVersion(rw.getVersion() + 1);
				beanDao.save(rd);
			}


		} else {
			logger.info("outTradeNo 已经存在 : " + outTradeNo);
		}
		StreamUtils.copy("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>", Charset.forName("utf8"), response.getOutputStream());
	}

	/**
	 * 竞猜日志查询
	 * 
	 * @param userId
	 * @return
	 */
	@GetMapping("/wecc/log/query")
	@ResponseBody
	public ListResult<CasinoLog> queryCasinoLog(Long userId) {
		if (userId == null) {
			throw new NoteException("userId 不能为空");
		}

		return new ListResult<CasinoLog>().setList(beanDao.quickQueryList(CasinoLog.class, "userId", userId));
	}

	// ------------------------------------------ h5
	// 支付----------------------------------------------------------------------------
	/**
	 * 预支付接口
	 * 
	 * @param userId
	 * @param amount
	 *            购买币的数量
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/wecc/h5/pay/prepay", method = RequestMethod.GET)
	@ResponseBody
	public GeneralResult<JSAPI> prepayH5(Long userId, Integer amount, String ip) throws Exception {
		if (userId == null || amount == null) {
			throw new NoteException("userId , amount 不能为空");
		}

		// fee = "0.01";

		File file = new ClassPathResource("/prepayh5.txt").getFile();

		String xml = FileUtils.readFileToString(file);

		String body = getSystemParaValue("wxpayMsg");
		String noncestr = "feifan250";
		String notifyUrl = getSystemParaValue("baseUrl") + "/v1/wecc/pay/notify";
		// String openid = "ofLmEwbf21cDMNSxWThSrc-VpVyg";
		String outTradeNo = getBillNum();

		int fee = (int) (getSystemParaValueDouble("weccBuy") * amount);
		OutTradeNoLog log = new OutTradeNoLog();
		log.setState(0);
		log.setOutTradeNo(outTradeNo);
		log.setUserId(userId);
		log.setFee(fee);
		log.setAmount(amount);
		beanDao.save(log);

		// 额外信息
		String attach = userId.toString() + "-" + outTradeNo + "-" + fee;
		// String ip = "127.0.0.1";

		// String fee = getSystemParaValue("registFee");
		String totalFee = fee + "";

		xml = xml.replace("$appid", WeiXinConf.WECCAPPID);
		xml = xml.replace("$attach", attach);
		xml = xml.replace("$body", body);
		xml = xml.replace("$mchid", WeiXinConf.WECC_SHOP_ID);
		xml = xml.replace("$noncestr", noncestr);
		xml = xml.replace("$notifyUrl", notifyUrl);
		xml = xml.replace("$outTradeNo", outTradeNo);
		xml = xml.replace("$ip", ip);
		xml = xml.replace("$totalFee", totalFee);

		String signStr = "appid=" + WeiXinConf.WECCAPPID + "&attach=" + attach + "&body=" + body + "&mch_id=" + WeiXinConf.WECC_SHOP_ID + "&nonce_str=" + noncestr + "&notify_url=" + notifyUrl + "&out_trade_no="
				+ outTradeNo + "&spbill_create_ip=" + ip + "&total_fee=" + totalFee + "&trade_type=MWEB&key=" + WeiXinConf.WECC_SHOP_SECRET;

		String sign = WeiXinUtils.getMD5Code(signStr).toUpperCase();
		xml = xml.replace("$sign", sign);

		String result = weiXinUtils.postNow(xml, "https://api.mch.weixin.qq.com/pay/unifiedorder");

		// 封装jsapi
		JSAPI api = new JSAPI();
		String appId = WeiXinConf.WECCAPPID;
		String signType = "MD5";
		String timeStamp = System.currentTimeMillis() / 1000 + "";
		Document doc = DocumentHelper.parseText(result);
		Element root = doc.getRootElement();
		String prepayId = root.element("prepay_id").getText();
		String mweb_url = root.element("mweb_url").getText();

		String signstr1 = "appId=" + appId + "&nonceStr=" + noncestr + "&package=prepay_id=" + prepayId + "&signType=MD5&timeStamp=" + timeStamp + "&key=" + WeiXinConf.WECC_SHOP_SECRET;
		logger.info("jsapi sign = " + signstr1);
		api.setAppId(appId);
		api.setNonceStr(noncestr);
		api.setPackage1("prepay_id=" + prepayId);
		api.setSignType(signType);
		api.setTimeStamp(timeStamp);
		api.setPaySign(DigestUtils.md5Hex(signstr1).toUpperCase());
		api.setMweb_url(mweb_url);
		logger.info(api.getPaySign() + " --- " + WeiXinUtils.getMD5Code(signstr1).toUpperCase());

		return new GeneralResult<JSAPI>().setValue(api);
	}
}
